home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / base / netkit-b.07a / netkit-b / NetKit-B-0.07A / tftpd / tftpd.c < prev   
Encoding:
C/C++ Source or Header  |  1996-07-20  |  12.6 KB  |  522 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. char copyright[] =
  35.   "@(#) Copyright (c) 1983 Regents of the University of California.\n"
  36.   "All rights reserved.\n";
  37.  
  38. /*
  39.  * From: @(#)tftpd.c    5.13 (Berkeley) 2/26/91
  40.  */
  41. char rcsid[] = 
  42.   "$Id: tftpd.c,v 1.5 1996/07/20 21:05:48 dholland Exp $";
  43.  
  44. /*
  45.  * Trivial file transfer protocol server.
  46.  *
  47.  * This version includes many modifications by Jim Guyton <guyton@rand-unix>
  48.  */
  49. #include <sys/types.h>
  50. #include <sys/ioctl.h>
  51. #include <sys/stat.h>
  52. #include <signal.h>
  53. #include <fcntl.h>
  54.  
  55. #include <sys/socket.h>
  56. #include <netinet/in.h>
  57. #include <arpa/tftp.h>
  58. #include <netdb.h>
  59.  
  60. #include <setjmp.h>
  61. #include <syslog.h>
  62. #include <stdio.h>
  63. #include <errno.h>
  64. #include <ctype.h>
  65. #include <string.h>
  66. #include <stdlib.h>
  67. #include <unistd.h>
  68.  
  69. #define    TIMEOUT        5
  70.  
  71. int synchnet(int);
  72. int readit(FILE *file, struct tftphdr **dpp, int convert);
  73. int writeit(FILE *file, struct tftphdr **dpp, int ct, int convert);
  74. void read_ahead(FILE *file, int convert /* if true, convert to ascii */);
  75. void write_behind(FILE *file, int convert);
  76.  
  77. struct formats;
  78. static void tftp(struct tftphdr *tp, int size);
  79. static void nak(int error);
  80. static void sendfile(struct formats *pf);
  81. static void recvfile(struct formats *pf);
  82.  
  83. extern    int errno;
  84. struct    sockaddr_in s_in = { AF_INET };
  85. int    peer;
  86. int    rexmtval = TIMEOUT;
  87. int    maxtimeout = 5*TIMEOUT;
  88.  
  89. #define    PKTSIZE    SEGSIZE+4
  90. char    buf[PKTSIZE];
  91. char    ackbuf[PKTSIZE];
  92. struct    sockaddr_in from;
  93. int    fromlen;
  94.  
  95. #define MAXARG    4
  96. char    *dirs[MAXARG+1];
  97.  
  98. int
  99. main(int ac, char **av)
  100. {
  101.     register struct tftphdr *tp;
  102.     register int n = 0;
  103.     int on = 1;
  104.  
  105.     ac--; av++;
  106.     while (ac-- > 0 && n < MAXARG)
  107.         dirs[n++] = *av++;
  108.     openlog("tftpd", LOG_PID, LOG_DAEMON);
  109.     if (ioctl(0, FIONBIO, &on) < 0) {
  110.         syslog(LOG_ERR, "ioctl(FIONBIO): %m\n");
  111.         exit(1);
  112.     }
  113.     fromlen = sizeof (from);
  114.     n = recvfrom(0, buf, sizeof (buf), 0,
  115.         (struct sockaddr *)&from, &fromlen);
  116.     if (n < 0) {
  117.         syslog(LOG_ERR, "recvfrom: %m\n");
  118.         exit(1);
  119.     }
  120.     /*
  121.      * Now that we have read the message out of the UDP
  122.      * socket, we fork and exit.  Thus, inetd will go back
  123.      * to listening to the tftp port, and the next request
  124.      * to come in will start up a new instance of tftpd.
  125.      *
  126.      * We do this so that inetd can run tftpd in "wait" mode.
  127.      * The problem with tftpd running in "nowait" mode is that
  128.      * inetd may get one or more successful "selects" on the
  129.      * tftp port before we do our receive, so more than one
  130.      * instance of tftpd may be started up.  Worse, if tftpd
  131.      * break before doing the above "recvfrom", inetd would
  132.      * spawn endless instances, clogging the system.
  133.      */
  134.     {
  135.         int pid;
  136.         int i, j;
  137.  
  138.         for (i = 1; i < 20; i++) {
  139.             pid = fork();
  140.             if (pid < 0) {
  141.                 sleep(i);
  142.                 /*
  143.                  * flush out to most recently sent request.
  144.                  *
  145.                  * This may drop some request, but those
  146.                  * will be resent by the clients when
  147.                  * they timeout.  The positive effect of
  148.                  * this flush is to (try to) prevent more
  149.                  * than one tftpd being started up to service
  150.                  * a single request from a single client.
  151.                  */
  152.                 j = sizeof from;
  153.                 i = recvfrom(0, buf, sizeof (buf), 0,
  154.                     (struct sockaddr *)&from, &j);
  155.                 if (i > 0) {
  156.                     n = i;
  157.                     fromlen = j;
  158.                 }
  159.             } else {
  160.                 break;
  161.             }
  162.         }
  163.         if (pid < 0) {
  164.             syslog(LOG_ERR, "fork: %m\n");
  165.             exit(1);
  166.         } else if (pid != 0) {
  167.             exit(0);
  168.         }
  169.     }
  170.     from.sin_family = AF_INET;
  171.     alarm(0);
  172.     close(0);
  173.     close(1);
  174.     peer = socket(AF_INET, SOCK_DGRAM, 0);
  175.     if (peer < 0) {
  176.         syslog(LOG_ERR, "socket: %m\n");
  177.         exit(1);
  178.     }
  179.     if (bind(peer, (struct sockaddr *)&s_in, sizeof (s_in)) < 0) {
  180.         syslog(LOG_ERR, "bind: %m\n");
  181.         exit(1);
  182.     }
  183.     if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
  184.         syslog(LOG_ERR, "connect: %m\n");
  185.         exit(1);
  186.     }
  187.     tp = (struct tftphdr *)buf;
  188.     tp->th_opcode = ntohs(tp->th_opcode);
  189.     if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
  190.         tftp(tp, n);
  191.     exit(1);
  192. }
  193.  
  194. int    validate_access();
  195.  
  196. struct formats {
  197.     char    *f_mode;
  198.     int    (*f_validate)();
  199.     void    (*f_send)(struct formats *);
  200.     void    (*f_recv)(struct formats *);
  201.     int    f_convert;
  202. } formats[] = {
  203.     { "netascii",    validate_access,    sendfile,    recvfile, 1 },
  204.     { "octet",    validate_access,    sendfile,    recvfile, 0 },
  205. #ifdef notdef
  206.     { "mail",    validate_user,        sendmail,    recvmail, 1 },
  207. #endif
  208.     { 0 }
  209. };
  210.  
  211. /*
  212.  * Handle initial connection protocol.
  213.  */
  214. static void
  215. tftp(struct tftphdr *tp, int size)
  216. {
  217.     register char *cp;
  218.     int first = 1, ecode;
  219.     register struct formats *pf;
  220.     char *filename, *mode = NULL;
  221.  
  222.     filename = cp = tp->th_stuff;
  223. again:
  224.     while (cp < buf + size) {
  225.         if (*cp == '\0')
  226.             break;
  227.         cp++;
  228.     }
  229.     if (*cp != '\0') {
  230.         nak(EBADOP);
  231.         exit(1);
  232.     }
  233.     if (first) {
  234.         mode = ++cp;
  235.         first = 0;
  236.         goto again;
  237.     }
  238.     for (cp = mode; *cp; cp++)
  239.         if (isupper(*cp))
  240.             *cp = tolower(*cp);
  241.     for (pf = formats; pf->f_mode; pf++)
  242.         if (strcmp(pf->f_mode, mode) == 0)
  243.             break;
  244.     if (pf->f_mode == 0) {
  245.         nak(EBADOP);
  246.         exit(1);
  247.     }
  248.     ecode = (*pf->f_validate)(filename, tp->th_opcode);
  249.     if (ecode) {
  250.         nak(ecode);
  251.         exit(1);
  252.     }
  253.     if (tp->th_opcode == WRQ)
  254.         (*pf->f_recv)(pf);
  255.     else
  256.         (*pf->f_send)(pf);
  257.     exit(0);
  258. }
  259.  
  260.  
  261. FILE *file;
  262.  
  263. /*
  264.  * Validate file access.  Since we
  265.  * have no uid or gid, for now require
  266.  * file to exist and be publicly
  267.  * readable/writable.
  268.  * If we were invoked with arguments
  269.  * from inetd then the file must also be
  270.  * in one of the given directory prefixes.
  271.  * Note also, full path name must be
  272.  * given as we have no login directory.
  273.  */
  274. int
  275. validate_access(char *filename, int mode)
  276. {
  277.     struct stat stbuf;
  278.     int    fd;
  279.     char *cp, **dirp;
  280.  
  281.     syslog(LOG_ERR, "tftpd: trying to get file: %s\n", filename);
  282.  
  283.     if (*filename != '/') {
  284.         syslog(LOG_ERR, "tftpd: serving file from %s\n", dirs[0]);
  285.         chdir(dirs[0]);
  286.     } else {
  287.         for (dirp = dirs; *dirp; dirp++)
  288.             if (strncmp(filename, *dirp, strlen(*dirp)) == 0)
  289.                 break;
  290.         if (*dirp==0 && dirp!=dirs)
  291.             return (EACCESS);
  292.     }
  293.     /*
  294.      * prevent tricksters from getting around the directory restrictions
  295.      */
  296.     for (cp = filename + 1; *cp; cp++)
  297.         if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0)
  298.             return(EACCESS);
  299.     if (stat(filename, &stbuf) < 0)
  300.         return (errno == ENOENT ? ENOTFOUND : EACCESS);
  301.     if (mode == RRQ) {
  302.         if ((stbuf.st_mode&(S_IREAD >> 6)) == 0)
  303.             return (EACCESS);
  304.     } else {
  305.         if ((stbuf.st_mode&(S_IWRITE >> 6)) == 0)
  306.             return (EACCESS);
  307.     }
  308.     fd = open(filename, mode == RRQ ? 0 : 1);
  309.     if (fd < 0)
  310.         return (errno + 100);
  311.     file = fdopen(fd, (mode == RRQ)? "r":"w");
  312.     if (file == NULL) {
  313.         return errno+100;
  314.     }
  315.     return (0);
  316. }
  317.  
  318. int    timeout;
  319. sigjmp_buf    timeoutbuf;
  320.  
  321. void
  322. timer()
  323. {
  324.  
  325.     timeout += rexmtval;
  326.     if (timeout >= maxtimeout)
  327.         exit(1);
  328.     siglongjmp(timeoutbuf, 1);
  329. }
  330.  
  331. /*
  332.  * Send the requested file.
  333.  */
  334. static void
  335. sendfile(struct formats *pf)
  336. {
  337.     struct tftphdr *dp, *r_init();
  338.     register struct tftphdr *ap;    /* ack packet */
  339.     volatile int block = 1;
  340.     int size, n;
  341.  
  342.     signal(SIGALRM, timer);
  343.     dp = r_init();
  344.     ap = (struct tftphdr *)ackbuf;
  345.     do {
  346.         size = readit(file, &dp, pf->f_convert);
  347.         if (size < 0) {
  348.             nak(errno + 100);
  349.             goto abort;
  350.         }
  351.         dp->th_opcode = htons((u_short)DATA);
  352.         dp->th_block = htons((u_short)block);
  353.         timeout = 0;
  354.         (void) sigsetjmp(timeoutbuf, 1);
  355.  
  356. send_data:
  357.         if (send(peer, dp, size + 4, 0) != size + 4) {
  358.             syslog(LOG_ERR, "tftpd: write: %m\n");
  359.             goto abort;
  360.         }
  361.         read_ahead(file, pf->f_convert);
  362.         for ( ; ; ) {
  363.             alarm(rexmtval);        /* read the ack */
  364.             n = recv(peer, ackbuf, sizeof (ackbuf), 0);
  365.             alarm(0);
  366.             if (n < 0) {
  367.                 syslog(LOG_ERR, "tftpd: read: %m\n");
  368.                 goto abort;
  369.             }
  370.             ap->th_opcode = ntohs((u_short)ap->th_opcode);
  371.             ap->th_block = ntohs((u_short)ap->th_block);
  372.  
  373.             if (ap->th_opcode == ERROR)
  374.                 goto abort;
  375.             
  376.             if (ap->th_opcode == ACK) {
  377.                 if (ap->th_block == block) {
  378.                     break;
  379.                 }
  380.                 /* Re-synchronize with the other side */
  381.                 (void) synchnet(peer);
  382.                 if (ap->th_block == (block -1)) {
  383.                     goto send_data;
  384.                 }
  385.             }
  386.  
  387.         }
  388.         block++;
  389.     } while (size == SEGSIZE);
  390. abort:
  391.     (void) fclose(file);
  392. }
  393.  
  394. void
  395. justquit()
  396. {
  397.     exit(0);
  398. }
  399.  
  400.  
  401. /*
  402.  * Receive a file.
  403.  */
  404. static void
  405. recvfile(struct formats *pf)
  406. {
  407.     struct tftphdr *dp, *w_init();
  408.     struct tftphdr *ap;    /* ack buffer */
  409.     volatile int block = 0;
  410.     int n, size;
  411.  
  412.     signal(SIGALRM, timer);
  413.     dp = w_init();
  414.     ap = (struct tftphdr *)ackbuf;
  415.     do {
  416.         timeout = 0;
  417.         ap->th_opcode = htons((u_short)ACK);
  418.         ap->th_block = htons((u_short)block);
  419.         block++;
  420.         (void) sigsetjmp(timeoutbuf, 1);
  421. send_ack:
  422.         if (send(peer, ackbuf, 4, 0) != 4) {
  423.             syslog(LOG_ERR, "tftpd: write: %m\n");
  424.             goto abort;
  425.         }
  426.         write_behind(file, pf->f_convert);
  427.         for ( ; ; ) {
  428.             alarm(rexmtval);
  429.             n = recv(peer, dp, PKTSIZE, 0);
  430.             alarm(0);
  431.             if (n < 0) {            /* really? */
  432.                 syslog(LOG_ERR, "tftpd: read: %m\n");
  433.                 goto abort;
  434.             }
  435.             dp->th_opcode = ntohs((u_short)dp->th_opcode);
  436.             dp->th_block = ntohs((u_short)dp->th_block);
  437.             if (dp->th_opcode == ERROR)
  438.                 goto abort;
  439.             if (dp->th_opcode == DATA) {
  440.                 if (dp->th_block == block) {
  441.                     break;   /* normal */
  442.                 }
  443.                 /* Re-synchronize with the other side */
  444.                 (void) synchnet(peer);
  445.                 if (dp->th_block == (block-1))
  446.                     goto send_ack;          /* rexmit */
  447.             }
  448.         }
  449.         /*  size = write(file, dp->th_data, n - 4); */
  450.         size = writeit(file, &dp, n - 4, pf->f_convert);
  451.         if (size != (n-4)) {                    /* ahem */
  452.             if (size < 0) nak(errno + 100);
  453.             else nak(ENOSPACE);
  454.             goto abort;
  455.         }
  456.     } while (size == SEGSIZE);
  457.     write_behind(file, pf->f_convert);
  458.     (void) fclose(file);            /* close data file */
  459.  
  460.     ap->th_opcode = htons((u_short)ACK);    /* send the "final" ack */
  461.     ap->th_block = htons((u_short)(block));
  462.     (void) send(peer, ackbuf, 4, 0);
  463.  
  464.     signal(SIGALRM, justquit);      /* just quit on timeout */
  465.     alarm(rexmtval);
  466.     n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
  467.     alarm(0);
  468.     if (n >= 4 &&                   /* if read some data */
  469.         dp->th_opcode == DATA &&    /* and got a data block */
  470.         block == dp->th_block) {    /* then my last ack was lost */
  471.         (void) send(peer, ackbuf, 4, 0);     /* resend final ack */
  472.     }
  473. abort:
  474.     return;
  475. }
  476.  
  477. struct errmsg {
  478.     int    e_code;
  479.     char    *e_msg;
  480. } errmsgs[] = {
  481.     { EUNDEF,    "Undefined error code" },
  482.     { ENOTFOUND,    "File not found" },
  483.     { EACCESS,    "Access violation" },
  484.     { ENOSPACE,    "Disk full or allocation exceeded" },
  485.     { EBADOP,    "Illegal TFTP operation" },
  486.     { EBADID,    "Unknown transfer ID" },
  487.     { EEXISTS,    "File already exists" },
  488.     { ENOUSER,    "No such user" },
  489.     { -1,        0 }
  490. };
  491.  
  492. /*
  493.  * Send a nak packet (error message).
  494.  * Error code passed in is one of the
  495.  * standard TFTP codes, or a UNIX errno
  496.  * offset by 100.
  497.  */
  498. static void
  499. nak(int error)
  500. {
  501.     register struct tftphdr *tp;
  502.     int length;
  503.     register struct errmsg *pe;
  504.  
  505.     tp = (struct tftphdr *)buf;
  506.     tp->th_opcode = htons((u_short)ERROR);
  507.     tp->th_code = htons((u_short)error);
  508.     for (pe = errmsgs; pe->e_code >= 0; pe++)
  509.         if (pe->e_code == error)
  510.             break;
  511.     if (pe->e_code < 0) {
  512.         pe->e_msg = strerror(error - 100);
  513.         tp->th_code = EUNDEF;   /* set 'undef' errorcode */
  514.     }
  515.     strcpy(tp->th_msg, pe->e_msg);
  516.     length = strlen(pe->e_msg);
  517.     tp->th_msg[length] = '\0';
  518.     length += 5;
  519.     if (send(peer, buf, length, 0) != length)
  520.         syslog(LOG_ERR, "nak: %m\n");
  521. }
  522.